package net.es.weathermap.path.idc;

import java.text.ParseException;
import java.util.*;

import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.SchedulerException;

import net.es.weathermap.beans.Domain;
import net.es.weathermap.beans.Node;
import net.es.weathermap.beans.Path;
import net.es.weathermap.path.PathProvider;
import net.es.weathermap.sched.FetchOscarsMetricsJob;
import net.es.weathermap.sched.FetchOscarsPathsJob;
import net.es.weathermap.sched.JobScheduler;
import net.es.weathermap.topo.network.ResvInfo;
import net.es.weathermap.topo.URNParser;
import net.es.weathermap.topo.URNParserResult;

import org.apache.log4j.Logger;

public class IDCPathProvider implements PathProvider {
    private static List<Path> paths;
    private Domain domain;
    private static Logger LOG = Logger.getLogger(IDCPathProvider.class);

    private static IDCPathProvider instance;
    public static IDCPathProvider getInstance(Domain dom) {
        if (instance == null) {
            instance = new IDCPathProvider(dom);
        }
        return instance;
    }

    public static IDCPathProvider getInstance() {
        return instance;
    }

    private IDCPathProvider(Domain dom) {
        domain = dom;
        // fetch paths
        this.fetchPaths();

        // schedule fetching paths every hour
        JobScheduler jsch = JobScheduler.getInstance();
        jsch.start();
        JobDetail jobDetail = new JobDetail("fp", "fp", FetchOscarsPathsJob.class);
        CronTrigger trig = null;
        try {
            // pull OSCARS data every 1h
            trig = new CronTrigger("fp", "fp", "0 0 * * * ?");
            jsch.getScheduler().scheduleJob(jobDetail, trig);
        } catch (ParseException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (SchedulerException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void fetchPaths() {
        ArrayList<Path> paths = new ArrayList<Path>();
        ArrayList<HashMap<String, String>> resvs =
            ResvInfo.getInstance(true).getReservations();
        for (HashMap<String,String> resv : resvs) {
            Path path = new Path();
            String gri = resv.get("gri");
            path.setTopoId(gri);
            path.setIdentifier(gri);
            path.setDescription(resv.get("description"));
            Integer bandwidth = Integer.valueOf(resv.get("bandwidth").trim());
            path.setBandwidth(bandwidth);
            String[] resvHops = resv.get("hops").split(",");
            String srcVlan = "";
            String dstVlan = "";
            if (resv.get("layer2").equals("_TRUE_")) {
                srcVlan = resv.get("srcVlan");
                dstVlan = resv.get("destVlan");
            }
            Node srcNode = null;
            Node dstNode = null;
            String srcIfceId = "";
            String dstIfceId = "";
            ArrayList<Node> hops = new ArrayList<Node>();
            ArrayList<String> hopIfces = new ArrayList<String>();

            for (String fqLinkId : resvHops) {
                URNParserResult res = URNParser.parseTopoIdent(fqLinkId, domain.getTopoId());
                String domainId = res.getDomainId();

                String nodeId = res.getNodeId();
                String portId = res.getPortId();
                if (domainId.equals(domain.getTopoId())) {
                    Node thisNode = domain.findNode(nodeId);
                    if (srcNode == null) {
                        srcNode = thisNode;
                        srcIfceId = nodeId+":"+portId;
                        if (!srcVlan.equals("")) {
                            srcIfceId = nodeId+":"+portId+"."+srcVlan;
                        }
                    }
                    dstNode = thisNode;
                    dstIfceId = nodeId+":"+portId;
                    if (!dstVlan.equals("")) {
                        dstIfceId = nodeId+":"+portId+"."+dstVlan;
                    }
                    String hopIfceId = nodeId+":"+portId;
                    hopIfces.add(hopIfceId);
                    if (!hops.contains(thisNode)) {
                        hops.add(thisNode);
                    }
                }
                path.setHopIfces(hopIfces);
                path.setHops(hops);
            }
            path.setDst(dstNode);
            path.setSrc(srcNode);
            path.setSrcIfceId(srcIfceId);
            path.setDstIfceId(dstIfceId);
            paths.add(path);
        }
        this.paths = paths;
    }


    public List<Path> getPaths(Domain dom) {
        return paths;
    }

    public void setDomain(Domain domain) {
        this.domain = domain;
    }

    public Domain getDomain() {
        return domain;
    }

}
